home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr49
/
112_01.zip
/
DISKDOC.C
< prev
next >
Wrap
Text File
|
1993-06-19
|
18KB
|
900 lines
/* TAB s5,4
*
* diskdoc
* a utility for diskette maintainance
*
* by egil kvaleberg
* studpost 111
* n7034 trondheim-nth
* norway
*
* diskdoc is intended for use and distribution
* among amateur computer users only. please respect this.
*
* compile using the Ron Cain small C compiler as distributed
* by The Code Works. if you use the version of the compiler shown
* in the Dr. Dobbs May 1980 issue, you must ensure that the stack
* is properly initialized. if you use another C compiler, you'll
* have to revise (parts of) the file ddocsys.c. good luck.
*/
#define VERSION "ver c - 1 nov 81"
#define WHOMADEIT "by egil kvaleberg"
/*
* constants, change as required
*/
#define SECLEN 128 /* sector length, 128 or 256 is ok */
#define VOID 229 /* character used when zeroing diskette */
#define DHOME 26 /* default home character */
#define ESC 27 /* lead-in character */
#define CR 13 /* various ascii equates */
#define LF 10
#define BS 8
#define QOT 39
/*
* globals
*/
int tracks, /* number of tracks and sectors */
sectors,firstsector;
int dfltrk,dflsec; /* default values */
char dfldrv;
char secbuf[SECLEN]; /* buffer for patch */
char vfybuf[SECLEN]; /* buffer for write verify */
int home; /* character to move cursor home */
/*
* begin
*/
main()
{ char cmd;
dfldrv='a'; dfltrk=0; dflsec=0;
home=DHOME;
if (sysok()==0) exit();
nl(); puts("welcome to the world of diskdoc ");
nl(); puts(VERSION); nl(); puts(WHOMADEIT);
nl(); nl(); puts("kindly enter your request");
cmd=0;
while (cmd!='e') {
nl();
puts("adapt, backup, compare, exit, patch, scan, test or zero ?");
cmd=getcmd("abcepstz",'e');
if (cmd=='a') adapt();
else if (cmd=='b') backup();
else if (cmd=='c') compare();
else if (cmd=='p') patch();
else if (cmd=='s') scan();
else if (cmd=='t') test();
else if (cmd=='z') zero();
else {
nl(); puts("re-insert the system diskette and type <cr> ");
if (conlower()!=CR) cmd=0;
nl();
}
}
nl(); puts("thanks for having consulted diskdoc");
exit();
}
/*
* adapt to terminal
*/
adapt()
{ nl(); nl(); puts("type character to move cursor home..");
putbyte(home=conin());
if (home==ESC) {
puts(".."); putbyte(home=conin());
home=home+128;
}
nl();
}
/*
* backup, copy entire diskette
*/
backup()
{ int trk,ftrk,ltrk;
char sdrive,ddrive; char *adr;
if (seltwo(&sdrive,&ddrive,
"source diskette in drive (a-h) ?",
"destination diskette in drive (a-h) ?")==0) return;
if (cont()==0) return;
trk=-1;
while (nextt(&trk)) {
adr=botmem();
ftrk=trk;
if (baksel(sdrive,ddrive,"source")==0) return;
while (1) {
if (readtrk(trk,adr)==0) return;
ltrk=trk;
adr=adr+(SECLEN*sectors);
if ((adr+(SECLEN*sectors))>=topmem()) break;
if (nextt(&trk)==0) break;
}
adr=botmem(); trk=ftrk;
if (baksel(ddrive,sdrive,"destination")==0) return;
while (1) {
if (writetrk(trk,adr)==0) {
puts("backup aborted"); nl();
return;
}
if (trk>=ltrk) break;
nextt(&trk);
adr=adr+(SECLEN*sectors);
}
}
nl(); puts("backup finished"); nl();
}
/*
* compare contents of two diskettes
*/
compare()
{ int trk,sec;
char drive1,drive2;
char *adr1,*adr2;
if (seltwo(&drive1,&drive2,
"compare diskette in drive (a-h) ?",
"to diskette in drive (a-h) ?")==0) return;
if (cont()==0) return;
trk=-1;
while (nextt(&trk)) {
adr1=botmem();
adr2=adr1+(SECLEN*sectors);
if (baksel(drive1,drive2,"first")==0) return;
if (readtrk(trk,adr1)==0) return;
if (baksel(drive2,drive1,"second")==0) return;
if (readtrk(trk,adr2)==0) return;
sec=firstsector-1;
while (nexts(&sec)) {
if (eqsec(adr1,adr2)==0) {
dfltrk=trk; dflsec=qskew(sec);
nl(); puts("compare error in "); putsec(dfltrk,dflsec);
}
adr1=adr1+SECLEN; adr2=adr2+SECLEN;
}
}
nl(); puts("compare finished"); nl();
}
/*
* zero diskette contents
*/
zero()
{ int trk,trkmax,n,m;
char *adr;
nl(); nl(); puts("zero diskette in drive (a-h) ?");
if (getsel()==0) return;
nl(); puts("zero how many tracks (0-"); putnum(tracks-1); puts(") ?");
trkmax=getnum(tracks-1,0,tracks-1);
if (cont()==0) return;
n=0; adr=botmem(); m=SECLEN*sectors;
while (n<m) adr[n++]=VOID;
trk=0;
while (trk<trkmax) {
if (writetrk(trk,botmem())==0) return;
nextt(&trk);
}
nl();
}
/*
* test a diskette by writing a pattern first,
* and then reading it back
*/
test()
{ int trk,sec,n;
char *adr,*p;
nl(); nl(); puts("diskette to test in drive (a-h) ?");
if (getsel()==0) return;
nl(); puts("the test will destroy the contents of the diskette");
if (cont()==0) return;
p="**** diskdoc **** test pattern *"; /* length is 32 */
n=0; /* fill pattern to compare to */
while (n<SECLEN) {
secbuf[n]=p[n&31];
++n;
}
puts("does diskette already contain test pattern (y-n) ?");
if (getcmd("yn",'n')=='n') {
nl(); puts("writing test pattern...");
trk=0; sec=firstsector-1;
while (next(&trk,&sec)) {
secbuf[0]=trk; secbuf[1]=qskew(sec);
if (tstbrk()) return 0;
if (write(trk,qskew(sec),secbuf)==0) {
nl(); puts("error writing "); putsec(trk,qskew(sec)); nl();
return 0;
}
}
}
trk=-1; /* read test */
nl(); puts("reading test pattern...");
while (nextt(&trk)) {
if (readtrk(trk,botmem())==0) return;
sec=firstsector-1; adr=botmem();
while (nexts(&sec)) {
secbuf[0]=trk; secbuf[1]=qskew(sec);
if (eqsec(adr,secbuf)==0) {
dfltrk=trk; dflsec=qskew(sec);
nl(); puts("bad test pattern in "); putsec(dfltrk,dflsec);
}
adr=adr+SECLEN;
}
}
nl(); puts("test completed"); nl();
}
/*
* scan: check all sectors for crc errors etc.
*/
scan()
{ int trk,sec;
nl(); nl(); puts("scan diskette in drive (a-h) ?");
if (getsel()==0) return;
if (cont()) {
nl();
trk=0; sec=firstsector-1;
while (next(&trk,&sec)) {
if (tstbrk()) return;
if (sec==firstsector) {
puts("track "); putnum(trk); conout(CR);
}
if (read(trk,qskew(sec),vfybuf)==0) {
puts("the dubious quality of ");
putsec(trk,qskew(sec)); puts(" has been detected"); nl();
dfltrk=trk; dflsec=qskew(sec);
}
}
puts("scan finished"); nl();
}
}
/*
* patch
*/
patch()
{ int pos;
nl(); nl(); puts("patch diskette in drive (a-h) ?");
if (getsel()==0) return;
if (dflsec<firstsector) dflsec=firstsector;
getsec(&dfltrk,&dflsec);
putnls(60); gohome();
puts("<sp>=next-byte, <bs>=previous-byte, <cr>=next-line, <hex>, ',");
nl();
puts("next, logical-next, trk-sec, re-read, shift-bit, write or quit ?");
putnls(4);
puts(" +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f");
puts(" 0123456789abcdef");
pos=pread();
while ((pos=patchcmd(pos))>=0);
putnls(60);
}
/*
* one patch command
* return new position, -1 if quit
*/
patchcmd(pos)
int pos;
{ char cmd,dig;
cmd=conlower();
if (cmd=='q') return -1;
else if (cmd==' ') pos=(pos+1)%SECLEN;
else if (cmd==BS) pos=(pos+SECLEN-1)%SECLEN;
else if (cmd==CR) pos=(pos+16)%SECLEN;
else if (cmd=='s') pos=pshift(pos);
else if (cmd=='n') pos=pnsect();
else if (cmd=='l') pos=plsect();
else if (cmd=='t') pos=psetts();
else if (cmd=='r') pos=pread();
else if (cmd=='w') pos=pwrite();
else if (cmd==QOT) {
conout(QOT);
cmd=conin();
conout(BS);
if (cmd==BS) tbyte(pos);
else pos=patchpos(pos,cmd);
}
else if ((dig=makhex(cmd))>=0) {
putdig(dig);
while ((cmd=conlower())!=BS) if (makhex(cmd)>=0) break;
conout(BS);
if (cmd==BS) tbyte(pos);
else pos=patchpos(pos,(dig<<4)+makhex(cmd));
}
return poscur(pos);
}
/*
* patch one byte, update screen
* and return new position
*/
patchpos(pos,new)
int pos,new;
{ int tpos;
secbuf[pos]=new;
tpos=pos++;
if (pos>=SECLEN) pos=0;
while (tbyte(tpos++)>0);
return pos;
}
/*
* shift one bit at current position
*/
pshift(pos)
int pos;
{ int tpos,byte,carry;
tpos=pos;
carry=0;
while (1) {
byte=secbuf[tpos]&255;
secbuf[tpos]=(byte>>1)|(carry<<7);
carry=byte&1;
if (tbyte(tpos++)==0) break;
}
return poscur(pos);
}
/*
* next sector
*/
pnsect()
{ next(&dfltrk,&dflsec);
return pread();
}
/*
* next logical sector
* useful only in systems with mapping between logical and physical
* sector numbers
*/
plsect()
{ lnext(&dfltrk,&dflsec);
return pread();
}
/*
* set new track/sector address
*/
psetts()
{ gohome(); putnls(2); putsps(38);
gohome(); nl();
getsec(&dfltrk,&dflsec);
return pread();
}
/*
* read and display one sector during patch
*/
pread()
{ char *p;
int pos;
pos=0;
while (pos<SECLEN) secbuf[pos++]=0;
gohome(); putnls(2);
if (read(dfltrk,dflsec,secbuf)==0) puts("error reading ");
putsec(dfltrk,dflsec);
putsps(18); nl(); putsps(24);
poscur(pos=0);
while (tbyte(pos++));
return poscur(0);
}
/*
* write one sector during patch
* verify by reading back
*/
pwrite()
{ int c;
gohome(); putnls(2); c=cont();
gohome(); putnls(3);
if (c) {
if (write(dfltrk,dflsec,secbuf)==0) puts("error writing");
else if (read(dfltrk,dflsec,vfybuf)==0) puts("error reading back");
else if (eqsec(secbuf,vfybuf)==0) puts("error on read verify");
}
putsps(22);
return poscur(0);
}
/*
* position cursor during patch
* position is returned
*/
poscur(pos)
int pos;
{ int n;
gohome(); putnls(6); puts("00 ");
n=pos/16; while (n--) conout(LF);
n=(pos/16)*16; while (n<pos) tbyte(n++);
return pos;
}
/*
* print byte in patch table
* returns -1 if end of line
* 0 if end of page
* 1 otherwise
*/
tbyte(pos)
int pos;
{ putbyte(secbuf[pos++]); /* print byte */
puts(" ");
if (pos%16) return 1;
puts(" '"); /* print ascii equivalents */
pos=pos-16;
while (1) {
conout(makep(secbuf[pos++]));
if ((pos%16)==0) break;
}
puts("'"); nl();
if (pos==SECLEN) return 0;
putbyte(pos); /* print address too */
puts(" ");
return -1;
}
/*
* read one track
* assume that drive is already selected
*/
readtrk(trk,adr)
int trk;
char *adr;
{ int sec;
char cmd;
sec=firstsector;
while (1) {
if (tstbrk()) return 0;
if (read(trk,qskew(sec),adr)==0) {
nl(); puts("error reading "); putsec(trk,qskew(sec));
nl(); puts("continue, retry or quit ?");
cmd=getcmd("qcr",'r');
if (cmd=='r') {
read(0,firstsector,vfybuf); /* reposition */
continue;
}
dfltrk=trk; dflsec=qskew(sec);
if (cmd=='q') return 0;
}
adr=adr+SECLEN;
if (nexts(&sec)==0) return 1;
}
}
/*
* write one track
*/
writetrk(trk,adr)
int trk;
char *adr;
{ int sec;
sec=firstsector;
while (1) {
if (tstbrk()) return 0;
if (write(trk,qskew(sec),adr)==0) {
nl(); puts("error writing "); putsec(trk,qskew(sec)); nl();
return 0;
}
adr=adr+SECLEN;
if (nexts(&sec)==0) return 1;
}
}
/*
* get track and sector numbers
*/
getsec(t,s)
int *t,*s;
{ nl(); puts("track (0-"); putnum(tracks-1); puts(") ?");
*t=getnum(*t,0,tracks-1);
nl(); puts("sector ("); putnum(firstsector); puts("-");
putnum(sectors-1+firstsector); puts(") ?");
*s=getnum(*s,firstsector,sectors-1+firstsector);
}
/*
* get drive name, select and reset
* 0 if cannot select
*/
getsel()
{ if (seldrv((dfldrv=getdrv(dfldrv)),&tracks,§ors,&firstsector)==0) {
nl(); puts("drive not ready"); nl();
return 0;
}
rstdrv();
return 1;
}
/*
* select two drives
* parameters of drives selected must be equivalent
*/
seltwo(d1,d2,text1,text2)
char *d1,*d2;
char *text1,*text2;
{ int dtracks,dsectors,dfirstsector;
nl(); nl(); puts(text1);
*d1=dfldrv=getdrv(dfldrv);
nl(); puts(text2);
*d2=getdrv(dfldrv);
seldrv(*d1,&tracks,§ors,&firstsector); /* establish constants */
rstdrv();
seldrv(*d2,&dtracks,&dsectors,&dfirstsector);
rstdrv();
if ((dtracks!=tracks)|(dsectors!=sectors)|(dfirstsector!=firstsector)) {
nl(); puts("drives are not compatible"); nl();
return 0;
}
return 1;
}
/*
* increment track and sector, 0 if no more
*/
next(t,s)
int *t,*s;
{ if (nexts(s)) return 1;
return nextt(t);
}
/*
* increment sector, 0 if no more
*/
nexts(s)
int *s;
{ if ((++*s)>(sectors-1+firstsector)) {
*s=firstsector;
return 0;
}
return 1;
}
/*
* increment track, 0 if no more
*/
nextt(t)
int *t;
{ if ((++*t)>=tracks) return *t=0;
return 1;
}
/*
* return skewed sector number, skew factor is two.
* this function is not equivalent to lnext().
* the only purpose of this function is to optimize
* scan and backup operations.
* hard disks will operate faster without a skew.
* hard disk is assumed if there are more than 100 tracks (!).
*/
qskew(sec)
int sec;
{ if (tracks>100) return sec;
sec=sec+sec-firstsector;
if (sec>(sectors-1+firstsector))
return sec-sectors+((sectors&1)==0);
return sec;
}
/*
* compare two sectors
* false if not equal
*/
eqsec(sec1,sec2)
char *sec1,*sec2;
{ int n;
n=0;
while (n<SECLEN) {
if (sec1[n]!=sec2[n]) return 0;
++n;
}
return 1;
}
/*
* select drive during backup
* return 0 if something fishy
*/
baksel(drv,otherdrv,name)
char drv,otherdrv; char *name;
{ int dummy;
if (drv==otherdrv) {
nl(); puts("insert "); puts(name); puts(" diskette");
if (cont()==0) return 0;
}
if (seldrv(drv,&dummy,&dummy,&dummy)==0) {
nl(); puts(name); puts(" drive is not ready"); nl();
return 0;
}
return 1;
}
/*
* get drive name, enter with default drive
*/
getdrv(dfl)
char dfl;
{ return getcmd("abcdefgh",dfl);
}
/*
* ask for continue or quit, true if continue
*/
cont()
{ char cmd;
nl(); puts("continue or quit ?");
cmd=getcmd("cq",'c'); nl();
return cmd=='c';
}
/*
* get single character command,
* enter with possible commands and default command
*/
getcmd(cmds,dfl)
char *cmds,dfl;
{ char cmd,ch;
while (1) {
if ((cmd=conlower())==CR) cmd=dfl;
if (member(cmd,cmds)==0) continue;
conout(cmd);
ch=0;
while (ch!=BS) if ((ch=conlower())==CR) return cmd;
unput();
}
}
/*
* see if character can be found in a string
*/
member(ch,str)
char ch,*str;
{ while (*str) if (*str++==ch) return 1;
return 0;
}
/*
* get a unsigned decimal number
* enter with default, minimun and maximum values
*/
getnum(dfl,min,max)
int dfl,min,max;
{ int n,digits,newn; char ch;
if (dfl>max) dfl=max;
n=digits=0;
while (1) {
if ((ch=conlower())==CR) {
if (digits) {
if (n>=min) break;
} else digits=putnum(n=dfl);
} else if (ch==BS) {
if (digits) {
--digits; n=n/10;
unput();
}
} else if (((makdec(ch))>=0) & ((newn=n*10+makdec(ch))<=max)) {
if ((newn>0)|(digits==0)) {
++digits; n=newn;
conout(ch);
}
}
}
return n;
}
/*
* make character printing
*/
makep(ch)
char ch;
{ ch=ch&127;
if ((ch>=' ')&(ch<127)) return ch;
return ' ';
}
/*
* put track and sector numbers
*/
putsec(t,s)
int t,s;
{ puts("track "); putnum(t);
puts(" sector "); putnum(s);
}
/*
* put decimal number,
* return number of digits printed
*/
putnum(n)
int n;
{ int d;
if (n>9) d=putnum(n/10);
else d=0;
putdig(n%10);
return d+1;
}
/*
* put hex byte
*/
putbyte(n)
int n;
{ putdig(n>>4);
putdig(n);
}
/*
* put digit
*/
putdig(d)
int d;
{ if ((d=d&15)>9) conout(d-10+'a');
else conout(d+'0');
}
/*
* put string
*/
puts(str)
char *str;
{ while (*str) conout(*str++);
}
/*
* put spaces
*/
putsps(n)
int n;
{ while (n--) conout(' ');
}
/*
* new line
*/
nl()
{ conout(CR); conout(LF);
}
/*
* put newlines
*/
putnls(n)
int n;
{ while (n--) nl();
}
/*
* erase previous character
*/
unput()
{ conout(BS); conout(' '); conout(BS);
}
/*
* move cursor to home position
*/
gohome()
{ if (home>=128) conout(ESC);
conout(home & 127);
}
/*
* convert decimal digit, -1 if error
*/
makdec(ch)
char ch;
{ if ((ch=ch-'0')<0) return -1;
if (ch<=9) return ch;
return -1;
}
/*
* convert hex digit, -1 if error
*/
makhex(ch)
char ch;
{ if (ch<'0') return -1;
if (ch<='9') return ch-'0';
if ((ch=ch-'a'+10)<10) return -1;
if (ch<=15) return ch;
return -1;
}
/*
* test for break, true if yes
*/
tstbrk()
{ if (const()) {
nl(); puts("break");
if (cont()==0) return 1;
}
return 0;
}
/*
* get character, no echo
* upper case is converted to lower
*/
conlower()
{ char ch;
ch=conin();
if ((ch>='A')&(ch<='Z')) ch=ch+'a'-'A';
return ch;
}
/*
* system dependant functions
*/
#include ddocsys.c
/*
* the small C runtime library (as shown in the Dr. Dobbs
* September 1980 issue and as distributed by The Code
* Works) must be named ddoclib and edited
* so that it contains the primitive functions only:
* ccgchar,ccgint,ccpchar,...,ccmult,ccdiv
*/
#include ddoclib